package com.lingjtx.common.security.handle;

import com.lingjtx.common.core.ResponseCode;
import com.lingjtx.common.core.ResponseResult;
import com.lingjtx.common.core.exception.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.resource.NoResourceFoundException;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 全局异常处理类
 *
 * @author John Liu
 */
@RestControllerAdvice
public class GlobalExceptionResolver {

    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionResolver.class);

    @ExceptionHandler(Exception.class)
    public ResponseResult<String> globalException(Exception e) {
        log.error("全局异常信息：{}", e.getMessage(), e);

        // 业务异常交由 sentinel 记录
//        Tracer.trace(e);
        return ResponseResult.createByError();
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseResult<String> paramCheckException(MethodArgumentNotValidException e) {
        log.warn("参数校验异常：{}", e.getMessage());
        return ResponseResult.createByError(String.format("参数校验错误: %s",
                e.getBindingResult()
                        .getFieldErrors()
                        .stream()
                        .map(FieldError::getDefaultMessage)
                        .collect(Collectors.joining(";"))));
    }

    /**
     * 处理业务校验过程中碰到的非法参数异常 该异常基本由{@link org.springframework.util.Assert}抛出
     *
     * @param e 参数校验异常
     * @return API返回结果对象包装后的错误输出结果
     * @see Assert#hasLength(String, String)
     * @see Assert#hasText(String, String)
     * @see Assert#isTrue(boolean, String)
     * @see Assert#isNull(Object, String)
     * @see Assert#notNull(Object, String)
     */
    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseResult<String> paramException(IllegalArgumentException e) {
        log.warn("非法参数异常：{}", e.getMessage());
        return ResponseResult.createByError("非法参数");
    }

    @ExceptionHandler(ParamCheckException.class)
    public ResponseResult<String> paramEmptyException() {
        log.warn("参数为空!!!");
        return ResponseResult.createByError(ResponseCode.PARAM_IS_NULL);
    }

    @ExceptionHandler(NoResourceFoundException.class)
    public ResponseResult<String> notFoundException(NoResourceFoundException e) {
        log.debug("请求路径 404 {}", e.getMessage());
        return ResponseResult.createByError(ResponseCode.RESOURCE_NOT_EXIST);
    }

    @ExceptionHandler(ForbiddenException.class)
    public ResponseResult<String> forbiddenException(ForbiddenException e) {
        log.debug("访问权限异常： {}", e.getMessage());
        return ResponseResult.createByError(ResponseCode.FORBIDDEN);
    }

    @ExceptionHandler(UnauthorizedException.class)
    public ResponseResult<String> unauthorizedException(UnauthorizedException e) {
        log.error("API KEY 验证错误：{}", e.getMessage());
        return ResponseResult.createByError(e.getResponse() == null ? ResponseCode.UNAUTHORIZED.getCode() : e.getResponse().getCode(), e.getMessage());
    }

    @ExceptionHandler(HasMustCompanyException.class)
    public ResponseResult<List> hasMustCompanyException(HasMustCompanyException e) {
        log.debug("该账号绑定多个组织/公司，请选择一个登录");
        return ResponseResult.createByError(ResponseCode.HAS_MUST_COMPANY, e.getRetResult());
    }

    @ExceptionHandler(ResponseErrorException.class)
    public ResponseResult<String> retErrorException(ResponseErrorException e) {
        log.warn("返回错误提示语异常： {}", e.getMessage());
        return ResponseResult.createByError(e.getMessage());
    }

    @ExceptionHandler(CaptchaException.class)
    public ResponseResult<Map<String, String>> captchaException(CaptchaException e) {
        log.warn("行为验证码异常： {}", e.getMessage());
        return ResponseResult.createByError(ResponseCode.CAPTCHA, e.getRetResult());
    }
}
